package com.darwin.darwinDll
{
	import com.darwin.darwinDll.analyze.AnalyzeDictionary;
	import com.darwin.darwinDll.analyze.IAnalyze;
	import com.darwin.darwinDll.analyze.JsonAnalyze;
	import com.darwin.darwinDll.core.Config;
	import com.darwin.darwinDll.core.DllItem;
	import com.darwin.darwinDll.core.DllLoader;
	import com.darwin.darwinDll.core.RemoteURLLoader;
	import com.darwin.darwinDll.core.ResKey;
	import com.darwin.darwinDll.event.DllEvent;
	import com.darwin.darwinUtils.Priority;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.system.ApplicationDomain;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * Dll资源管理器 
	 * @author vanCopper
	 * 
	 */	
	public class Dll extends EventDispatcher
	{
		private static var _instance:Dll;
		
		/**
		 * 文件加载器 
		 */		
		private var _dllLoader:DllLoader;
		
		private var _lang:String = "cn";
		private var _iniFolderUrl:String = "";
		private var _outFolderUrl:String = "";
		
		public function Dll()
		{
			if(_instance == null){
				_instance = this;
				init();
			}
			else{throw new Error("实例化单例类出错-Dll");}
		}
		
		private function init():void
		{
			_dllLoader = new DllLoader(RemoteURLLoader);
			_dllLoader.addEventListener(DllEvent.GROUP_COMPLETE,groupComplete);
			_dllLoader.addEventListener(DllEvent.GROUP_PROGRESS,groupProgress);
			_dllLoader.addEventListener(DllEvent.PROGRESS,onLoadProgress);
		}
		
		/**
		 * 列表加载进度 
		 * @param event
		 * 
		 */		
		protected function onLoadProgress(event:DllEvent):void
		{
			var dllItem:DllItem = event.data as DllItem;
			if(_matDllItemDic[dllItem.name])
			{
				var resKeyList:Array = _matResKeyDic[dllItem];
				var tempResKey:ResKey = resKeyList[0];
				var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(tempResKey.type);
				var data:* = analyze.getData(tempResKey.key,tempResKey.subKey);
				var completeFuncList:Array = _matFuncDic[dllItem];
//				var resKey:ResKey = _matResKeyDic[dllItem];
				for (var i:int = 0; i < completeFuncList.length; i++) 
				{
					var func:Function = completeFuncList[i];
					var resKey:ResKey = resKeyList[i];
					if(resKey.other != null)
					{
						var backObj:Object = {};
						backObj["data"] = data;
						backObj["resKey"] = resKey;
						func(backObj);
					}else
					{
						func(data);
					}
				}
				delete _matDllItemDic[dllItem.name];
				delete _matFuncDic[dllItem];
				delete _matResKeyDic[dllItem];
			}
		}
		
		/**
		 * 组加载进度 
		 * @param event
		 * 
		 */		
		private function groupProgress(event:DllEvent):void
		{
			if(event.groupName == GROUP_LOADING)
			{
				var loadingProgressEvent:DllEvent = new DllEvent(DllEvent.LOADING_PROGRESS);
				loadingProgressEvent.progress = event.progress;
				dispatchEvent(loadingProgressEvent);
			}
			
			if(event.groupName == GROUP_MAIN)
			{
				var mainProgressEvent:DllEvent = new DllEvent(DllEvent.MAIN_PROGRESS);
				mainProgressEvent.progress = event.progress;
				dispatchEvent(mainProgressEvent);
			}
		}
		
		/**
		 * 组加载完成 
		 * @param event
		 * 
		 */		
		private function groupComplete(event:DllEvent):void
		{
			var groupName:String = event.groupName;
			var dataList:Vector.<DllItem> = event.data as Vector.<DllItem>;
			if(groupName == GROUP_XML_CONFIG)
			{
				var xmlList:Vector.<XML> = new Vector.<XML>();
				for (var i:int = 0; i < dataList.length; i++) 
				{
					var item:DllItem = dataList[i];
					xmlList.push((item.result as XML));
				}
				
				Config.getInstance().initXmlConfig(xmlList,configComplete);
			}
			
			//loading组加载完成
			if(groupName == GROUP_LOADING)
			{
				var dllEvent:DllEvent = new DllEvent(DllEvent.LOADING_COMPLETE);
				dllEvent.progress = "1";
				dispatchEvent(dllEvent);
			}
			
			//Main组加载完成
			if(groupName == GROUP_MAIN)
			{
				var mainDllEvent:DllEvent = new DllEvent(DllEvent.MAIN_COMPLETE);
				mainDllEvent.progress = "1";
				mainDllEvent.data = event.data;
				dispatchEvent(mainDllEvent);
			}
			
			//请求加载的模块是否加载完成
			if(_moduleCallBackDic[groupName])
			{
				var modulecallBackFuncList:Array = _moduleCallBackDic[groupName];
				for (var n:int = 0; n < modulecallBackFuncList.length; n++) 
				{
					var moduleCallBackFunc:Function = modulecallBackFuncList[n];
					moduleCallBackFunc(dataList);
				}
				delete _moduleCallBackDic[groupName];
			}
			
			//请求加载预加载列表完成
			if(_preloadResDic[groupName])
			{
				var obj:Object = _preloadResDic[groupName];
				var resKeyList:Array = obj["resKeyList"];
				var completeFunc:Function = obj["completeFunc"];
				for each (var resKey:ResKey in resKeyList) 
				{
					var callAnalyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(resKey.type);
					var data:* = callAnalyze.getData(resKey.key,resKey.subKey);
					resKey.data = data;
				}
				completeFunc(resKeyList);
				delete _preloadResDic[groupName];
			}
			
			//异步请求预加载文件 加载完成
			if(groupName == GROUP_ASYNS_RES)
			{
				if(dataList && dataList.length)
				{
					for (var j:int = 0; j < dataList.length; j++) 
					{
						var dllItem:DllItem = dataList[j];
						var callBackList:Array = _asyncResItemDic[dllItem.name];
//						if(!callBackList)return;
						for (var k:int = 0; k < callBackList.length; k++) 
						{
							var resObj:Object = callBackList[k];
							var key:String = resObj["key"];
							var subKey:String = resObj["subKey"];
							var resCompleteFunc:Function = resObj["completeFunc"];
							var type:String = resObj["type"];
							var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(type);
							var resData:* = analyze.getData(key,subKey);
							resCompleteFunc(resData);
						}
						delete _asyncResItemDic[dllItem.name];
					}
					
				}
			}
		}
		
		/**
		 * 开始加载Main组文件 
		 * 
		 */		
		public function loadMainMoudle(isRealProgress:Boolean = false):void
		{
			//开始加载main组文件
			var mainList:Vector.<DllItem> = Config.getInstance().getMoudleDllItemList(GROUP_MAIN);
			_dllLoader.loadGroup(mainList,GROUP_MAIN,Priority.HIGH,isRealProgress);
		}
		
		/**
		 * 初始化配置文件解析完成 
		 * 执行初始化加载 
		 * 
		 */		
		private function configComplete():void
		{
			var loadingList:Vector.<DllItem> = Config.getInstance().getMoudleDllItemList(GROUP_LOADING);
			_dllLoader.loadGroup(loadingList,GROUP_LOADING);
			var dllEvent:DllEvent = new DllEvent(DllEvent.CONFIG_COMPLETE);
			dllEvent.progress = "1";
			dispatchEvent(dllEvent);
		}
		
		public static function getInstance():Dll
		{
			if(_instance == null)
			{
				_instance = new Dll();
			}
			return _instance;
		}
		
		/**
		 * 用于保存 预先加载列表中的 Reskey和completeFunc
		 * _preloadResDic[getTime()] = {"resKeyList":resKeyList,"completeFunc":completeFunc}
		 * (哎，蛋疼的各种 Dictionary)  
		 */		
		private var _preloadResDic:Dictionary = new Dictionary();
		/**
		 * 获取预先加载素材列表
		 * @param resKeyList ResKey类型 列表中多个Reskey表示 获取多个素材
		 * @param completeFunc Function参数为加载完成的资源列表
		 * 
		 */		
		public function getPreloadResList(resKeyList:Array,completeFunc:Function):void
		{
			var groupName:String = String(getTimer());
			var groupList:Vector.<DllItem> = new Vector.<DllItem>();
			_preloadResDic[groupName] = {"resKeyList":resKeyList,"completeFunc":completeFunc};
			for (var i:int = 0; i < resKeyList.length; i++) 
			{
				var resKey:ResKey = resKeyList[i];
				var dllItem:DllItem = Config.getInstance().getDllItemByName(resKey.key);
				groupList.push(dllItem);
			}
			_dllLoader.loadGroup(groupList,groupName);
		}
		
		/**
		 * 同步获取预先加载素材 
		 * @param key 对应文件名
		 * @param subKey swf文件内的导出类名
		 * @param type 文件类型
		 * @return 
		 * 
		 */		
		public function getSynPreloadRes(key:String = "",subKey:String = "",type:String = ""):*
		{
			if(type == "")
			{
				type = Config.getInstance().getItemTypeByName(key);
			}
			
			var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(type);
			var data:*;
			if(analyze)
			{
				data = analyze.getData(key,subKey);
			}
			return data;
		}
		
		/**
		 * 当异步获取素材时 用来存放请求加载的DllItem对应的 key,subKey,completeFunc,type
		 * _asyncResItemDic[dllItem.name] = [{"key":key,"subKey":subKey,"compelteFunc":completeFunc,"type":type}]; 
		 */		
		private var _asyncResItemDic:Dictionary = new Dictionary();
		/**
		 * 异步获取预加载素材
		 * @param key  img,xml,json,ddd,sound,swf key对应文件名 
		 * 需要在subkey参数中传递 对应的swf对应资源中导出类 名
		 * @param completeFunc
		 * @param type
		 * @param subKey
		 * @param priority 加载优先级
		 * 
		 */		
		public function getAsyncPreloadRes(key:String,completeFunc:Function,type:String = "",subKey:String = "",priority:int = Priority.MEDIUM):void
		{
			if(type == "")
			{
				type = Config.getInstance().getItemTypeByName(key);
			}
			
			var data:* = getSynPreloadRes(key,subKey,type);
			if(data != null)
			{
				completeFunc(data);
			}else
			{
				var dllItem:DllItem = Config.getInstance().getDllItemByName(key);
				dllItem.priority = priority;
				var dllItemList:Vector.<DllItem> = new Vector.<DllItem>();
				
				if(dllItem.status == DllItem.STATUS_NOT_LOADED)
				{
					dllItem.status = DllItem.STATUS_LOADING;
					dllItemList.push(dllItem);
				}
				
				if(_asyncResItemDic[dllItem.name])
				{
					var tempArr:Array = _asyncResItemDic[dllItem.name];
					tempArr.push({"key":key,"subKey":subKey,"completeFunc":completeFunc,"type":type});
//					_asyncResItemDic[dllItem.name] = tempArr;
				}else
				{
					_asyncResItemDic[dllItem.name] = [{"key":key,"subKey":subKey,"completeFunc":completeFunc,"type":type}];
				}
				
				if(dllItemList.length > 0)
				{
					_dllLoader.loadGroup(dllItemList,GROUP_ASYNS_RES,priority);
				}
			}
		}
		
		/**
		 * 获取某种类别的资源 
		 * @param type  DllItem.TYPE_SWF DllItem.TYPE_JSON .....
		 * 
		 */		
		public function getDataListByType(type:String):Dictionary
		{
			var returnDic:Dictionary;
			if(type != null && type != "")
			{
				var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(type);
				if(analyze != null)
				{
					returnDic = analyze.getDataList();
				}
			}
			return returnDic;
		}
		
		/**
		 * 用于保存请求加载外部素材的加载项
		 * _matDllItemDic[key+"$"+subKey] = DllItem; 
		 */		
		private var _matDllItemDic:Dictionary = new Dictionary();
		
		/**
		 * 用于保存请求加载外部素材的ResKey
		 * _matResKeyDic[DllItem]  = ResKey
		 */		
		private var _matResKeyDic:Dictionary = new Dictionary();
		
		/**
		 *  用于保存请求加载外部素材的completeFunc
		 * _matFuncDic[DllItem] = [completeFunc]; 
		 */		
		private var _matFuncDic:Dictionary = new Dictionary();
		/**
		 * 获取外部素材
		 * @param key 一般是对应素材id
		 * @param completeFunc 回调函数
		 * @param subKey 对应素材的第二个索引
		 * @param priority 加载优先级
		 * @param type 素材类型 默认为： DllItem.TYPE_SWF;
		 * @param other 其他标记信息 传参给回调方法
		 */		
		public function getMatRes(key:String,completeFunc:Function,subKey:String="",priority:int = Priority.LOW,type:String=DllItem.TYPE_SWF,other:Object = null):void
		{
			var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(type);
			var data:* = analyze.getData(key,subKey);
			var resKey:ResKey = new ResKey(key,subKey,type,other);
			var obj:Object = Config.getInstance().getMatObj(key,subKey);
			if(data==null)
			{
				if(analyze is JsonAnalyze)//如果目标类型为json，尝试通过url获取数据
				{
					data = (analyze as JsonAnalyze).getDataByUrl(obj["swfurl"]);
				}
			}
			
			if(data)//素材已被加载解析过
			{
				if(resKey.other != null)
				{
					var backObj:Object = {};
					backObj["data"] = data;
					backObj["resKey"] = resKey;
					completeFunc(backObj);
				}else
				{
					completeFunc(data);
				}
				return;
			}
			
			var indexKey:String = key + "$" + subKey;
//			var indexKey:String = obj["swfurl"];
			if(obj==null)
			{
				completeFunc(null);
				return;
			}
			
			var pDllItem:DllItem = _matDllItemDic[indexKey];
			if(pDllItem!=null)
			{
				var funcList:Array = _matFuncDic[pDllItem]; 
				var resKeyList:Array = _matResKeyDic[pDllItem];
				if(funcList)
				{
					funcList.push(completeFunc);
					resKeyList.push(resKey);
				}
				return;
			}
			
			var dllItem:DllItem = new DllItem(outFolderUrl + obj["swfurl"],indexKey,null,priority,type);
			_matDllItemDic[indexKey] = dllItem;
			//TODO 当同一素材 请求是使用了 不同的other/resKey数据 那么之前注册的就会被覆盖
			_matResKeyDic[dllItem] = [resKey];
			
			_matFuncDic[dllItem] = [completeFunc];
			
			var itemList:Vector.<DllItem> = new Vector.<DllItem>();
			itemList.push(dllItem);
			_dllLoader.insert(itemList);
		}
		
		/**
		 * 获取一组外部素材 
		 * @param resKeyList 数组里为 ResKey类型
		 * @param completeFunc
		 * @param priority 加载优先级
		 * @param type
		 */		
		public function getMatResList(resKeyList:Array,completeFunc:Function,priority:int = Priority.LOW,type:String = DllItem.TYPE_SWF):void
		{
			var groupName:String = String(getTimer());
			var groupList:Vector.<DllItem> = new Vector.<DllItem>();
			_preloadResDic[groupName] = {"resKeyList":resKeyList,"completeFunc":completeFunc};
			for (var i:int = 0; i < resKeyList.length; i++) 
			{
				var resKey:ResKey = resKeyList[i];
				var obj:Object = Config.getInstance().getMatObj(resKey.key,resKey.subKey);
				if(obj != null)
				{
					var name:String = resKey.key + "$" + resKey.subKey;
					var dllItem:DllItem = new DllItem(outFolderUrl + obj["swfurl"],name,null,priority,type);
					groupList.push(dllItem);
				}
			}
			_dllLoader.loadGroup(groupList,groupName);
		}
		
		/**
		 * 设置项目配置文件 
		 * @param configFileList ex::配置文件地址列表 ["ini.xml","outini.xml"]
		 * 
		 */		
		public function setInitConfig(configFileList:Array):void
		{
			var configList:Vector.<DllItem> = new Vector.<DllItem>();
			for (var i:int = 0; i < configFileList.length; i++) 
			{
				var dllItem:DllItem = new DllItem(configFileList[i],configFileList[i]);
				dllItem.groupName = GROUP_XML_CONFIG;
				dllItem.type = DllItem.TYPE_XML;
				configList.push(dllItem);
			}
			_dllLoader.loadGroup(configList,GROUP_XML_CONFIG);
		}
		
		private var _moduleCallBackDic:Dictionary = new Dictionary();//保存请求模块加载的回调方法
		/**
		 * 请求加载模块资源 
		 * @param moduleName 模块名称
		 * @param callBackFunc callBackFunc回调参数为 Vector.<DllItem>
		 * 
		 */		
		public function loadModule(moduleName:String,callBackFunc:Function = null):void
		{
			var moduleList:Vector.<DllItem> = Config.getInstance().getMoudleDllItemList(moduleName);
			if(moduleList && moduleList.length)
			{
				if(_moduleCallBackDic[moduleName])
				{
					var tempArr:Array = _moduleCallBackDic[moduleName];
					_moduleCallBackDic[moduleName] = tempArr.concat([callBackFunc]);
				}else
				{
					_moduleCallBackDic[moduleName] = [callBackFunc];
				}
				_dllLoader.loadGroup(moduleList,moduleName);
			}
		}
		
		/**
		 * 注册一个解析类 
		 * @param key 解析文件类型
		 * @param analyzeClass
		 * 
		 */		
		public function registerAnalyze(key:String,analyzeClass:Class):void
		{
			AnalyzeDictionary.getInstance().registerAnalyze(key,analyzeClass);
		}

		/**
		 * 当前语言环境 
		 */
		public function get lang():String
		{
			return _lang;
		}

		/**
		 * @private
		 */
		public function set lang(value:String):void
		{
			_lang = value;
		}

		/**
		 * 内部文件路径 
		 */
		public function get iniFolderUrl():String
		{
			return _iniFolderUrl;
		}

		/**
		 * @private
		 */
		public function set iniFolderUrl(value:String):void
		{
			_iniFolderUrl = value;
		}

		/**
		 * 外部文件路径 
		 */
		public function get outFolderUrl():String
		{
			return _outFolderUrl;
		}

		/**
		 * @private
		 */
		public function set outFolderUrl(value:String):void
		{
			_outFolderUrl = value;
		}

		
		/**
		 * 配置文件加载组 
		 */		
		public static const GROUP_XML_CONFIG:String = "config";
		/**
		 * loading预加载组 
		 */		
		public static const GROUP_LOADING:String = "loading";
		/**
		 *  初始化预加载组
		 */		
		public static const GROUP_MAIN:String = "main";
		/**
		 * 异步加载的预加载组 
		 */		
		public static const GROUP_ASYNS_RES:String = "asyn";
	}
}